#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright 2007 Denis Kürov
# Licensed under the GNU General Public License, version 3.
# See the file http://www.gnu.org/copyleft/gpl.txt.


from django.db import models
from django.db.models import signals
from django.dispatch import dispatcher

from iptables.dbwork.signals import remove_rule_action,unload_rule,new_iptables_entry,remove_iptables_entry,flush_child,del_iptables_chain



class Chain(models.Model):
    """ The chain of the rules"""
    
    name=models.CharField(max_length=30)
    description=models.TextField(max_length=50)
    
    def __unicode__(self):
        return self.name
        
    class Admin:
        list_display = ('id','name')
        

dispatcher.connect(del_iptables_chain,signal=signals.pre_delete, sender=Chain)


    
class Target(models.Model):
    """ The targets place drop..."""
    
    name=models.CharField(max_length=30)
    description=models.TextField(max_length=50)
    
    def __unicode__(self):
        return self.name
    
    
    class Admin:
        pass
    
    
class Rule(models.Model):
    """ The actual rule and the main part of others ..."""
    
    #define the foreign kesy firstly...
    parent_chain=models.ForeignKey(Chain)
    parent_target=models.ForeignKey(Target)
    
    #generic parts
    name=models.CharField(max_length=20)
    #source ip
    sip=models.CharField(max_length=70)
    #destination ip
    dip=models.CharField(max_length=70)
    #source interface
    s_interface=models.CharField(max_length=20)
    #destnation interface
    d_interface=models.CharField(max_length=20)
    #is it loaded
    loaded=models.BooleanField()
    
    
    
    def __unicode__(self):
        return self.name
    
    
    class Admin:
        
        list_display = ('id','name','parent_chain','parent_target','loaded')
        ordering=["parent_chain"]
    

class Tcp(models.Model):
    """ The tcp option id present for the rule"""
    
    #The parent rule :
    parent_rule=models.ForeignKey(Rule)
    
    sport=models.CharField(max_length=30)
    dport=models.CharField(max_length=30)
    tcp_flag=models.CharField(max_length=80)
    
    class Admin:
        pass


dispatcher.connect(flush_child,signal=signals.post_save, sender=Tcp)
dispatcher.connect(flush_child,signal=signals.post_delete, sender=Tcp)


class Icmp(models.Model):
    """ The model for the icmp type"""
    parent_rule=models.ForeignKey(Rule)
    icmp_type=models.CharField(max_length=35)
    
    class Admin:
        pass

dispatcher.connect(flush_child,signal=signals.post_save, sender=Icmp)
dispatcher.connect(flush_child,signal=signals.post_delete, sender=Icmp)

    
class Udp(models.Model):
    """ The udp option id present for the rule"""
    
    #The parent rule :
    parent_rule=models.ForeignKey(Rule)
    
    sport=models.CharField(max_length=30)
    dport=models.CharField(max_length=30)
    
    class Admin:
        pass

dispatcher.connect(flush_child,signal=signals.post_save, sender=Udp)
dispatcher.connect(flush_child,signal=signals.post_delete, sender=Udp)
    

class Optional(models.Model):
    """ The rules taht are exclusive option in iptables -m"""
    
    parent_rule=models.ForeignKey(Rule)
    
    #b_takip bu
    ctstaus =models.CharField(max_length=60)
    #paket limit bu
    mlength =models.CharField(max_length=35)
    #baglanti limit bu
    mlimit =models.CharField(max_length=50)
    #mac limit bu
    mac =models.CharField(max_length=40)
    #b durum du
    state =models.CharField(max_length=50)
    
    
    class Admin:
        pass
    
dispatcher.connect(flush_child,signal=signals.post_save, sender=Optional)
dispatcher.connect(flush_child,signal=signals.post_delete, sender=Optional)



class Loadindex(models.Model):
    """ That table is for plug and play every rule we want to see"""
    
    parent_rule=models.ForeignKey(Rule)
    
    ordering=models.IntegerField()
    
    def chain_name(self):
        """ Gets the name of the chain"""
        return self.parent_rule.parent_chain.name
    
    def __unicode__(self):
        return self.parent_rule.name
    
    class Admin:
        list_display = ('ordering','parent_rule','id','chain_name')
        ordering=["ordering"]

#when we add a new entry to         
dispatcher.connect(new_iptables_entry,signal=signals.pre_save, sender=Loadindex)
dispatcher.connect(remove_iptables_entry,signal=signals.post_delete, sender=Loadindex)
    
    
    
    
class Prefixer(models.Model):
    """ That keeps the prefixes we need for Logging"""
    
    parent_rule=models.ForeignKey(Rule)
    
    pref_name=models.CharField(max_length=29)
    
    class Admin:
        list_display = ('parent_rule','pref_name')
        ordering=["pref_name"]
        
dispatcher.connect(flush_child,signal=signals.post_save, sender=Prefixer)
dispatcher.connect(flush_child,signal=signals.post_delete, sender=Prefixer)
    

class Logs(models.Model):
    """ The actual logs that are recorded for prefix name"""
    parent_prefix=models.ForeignKey(Prefixer)
    
    log_date=models.DateTimeField()
    in_dev =models.CharField(max_length=10)
    outDev =models.CharField(max_length=10)
    ip_src =models.IPAddressField()
    ip_dst =models.IPAddressField()
    proto =models.CharField(max_length=10)
    sport =models.IntegerField()
    dport =models.IntegerField()
    
    class Admin:
        pass

#################################The signals part is here ##################################################   

def make_new_target(sender, instance, signal, *args,**kwargs):
    """ Creates a new target after you create a new chain
    Also connect it to the signal proper signal
    *Added later* If the chain or is edited or added we should flushh all iptables rules"""
    
    from iptables.dbwork.rulegen import IptablesRunner
    
    
    default_chains=['FORWARD','INPUT','OUTPUT']
    
    if instance.name not in default_chains:
        res=Target.objects.filter(name=instance.name)
        
        if not res:
            t=Target(name=instance.name,description=instance.description)
            t.save()
            
    IptablesRunner.flush_signal()
        #else:
            #res[0].name=instance.name
            #res[0].description=instance.description
            #res[0].save()
        
    
dispatcher.connect(make_new_target,signal=signals.post_save, sender=Chain)

def del_target(sender, instance, signal, *args,**kwargs):
    """ Deletes a target after a chain with the same name wa deleted """
    res=Target.objects.filter(name=instance.name)
    
    if res:
        res[0].delete()
        

dispatcher.connect(del_target,signal=signals.post_delete, sender=Chain)        
    #thats all

def before_save(sender, instance, signal, *args,**kwargs):
    """ If it was an update operation that is the way todo it 
    *Added later* If it is a new one we should call iptables -N chain_name"""
        
    ch=sender.objects.filter(id=instance.id)
    if ch:
        
        res=Target.objects.filter(name=ch[0].name)
        if res:
            res[0].name=instance.name
            res[0].description=instance.description
            res[0].save()

dispatcher.connect(before_save,signal=signals.pre_save, sender=Chain)        



#when removing a rule to not destroy all the things           
dispatcher.connect(remove_rule_action,signal=signals.pre_delete, sender=Rule)            
            
#when changing the tick from True to fasle we should remove it drom LoadUndex thing            
dispatcher.connect(unload_rule,signal=signals.pre_save, sender=Rule)        
        
#the syncdn thingy
#dispatcher.connect(unload_rule,signal=signals.pre_save, sender=Rule) 
#from iptables import models as ip_app
#from django.db.models import signals
from iptables.dbwork.signals import start_flush
#from django.dispatch import dispatcher
	
dispatcher.connect(start_flush,signal=signals.post_syncdb)

    
if __name__=="__main__":
    pass
                    
                    
    
    
